﻿/**********************************************************************
* Description:  A collection of data-type utility classes 
* Created By:	Dallon Feldner @ Central Christian Church of the East Valley
* Date Created:	???
*
* $Workfile: DataUtils.cs $
* $Revision: 18 $ 
* $Header: /trunk/Arena.Custom.Cccev/Arena.Custom.Cccev.DataUtils/DataUtils.cs   18   2009-08-19 13:21:59-07:00   nicka $
* 
* $Log: /trunk/Arena.Custom.Cccev/Arena.Custom.Cccev.DataUtils/DataUtils.cs $
*  
*  Revision: 18   Date: 2009-08-19 20:21:59Z   User: nicka 
*  Updated GetFractionalAge to use 3 decimal precision to match Arena 2009.1 
*  min/max age values in Attendance Types 
*  
*  Revision: 17   Date: 2009-03-23 21:57:45Z   User: DallonF 
*  Fixed ToInt32's handling of null strings 
*  
*  Revision: 16   Date: 2009-03-21 23:50:04Z   User: nicka 
*  Corrected another index out of range (Index and length must refer to a 
*  location within the string. Parameter name: length) bug. 
*  
*  Revision: 15   Date: 2009-03-16 17:58:50Z   User: JasonO 
*  
*  Revision: 14   Date: 2009-03-02 23:18:25Z   User: nicka 
*  Added intelligence to string.ToInt32() 
*  
*  Revision: 13   Date: 2009-02-26 00:05:50Z   User: DallonF 
*  Added string.ToInt32() 
*  
*  Revision: 12   Date: 2009-02-24 15:15:05Z   User: JasonO 
*  
*  Revision: 11   Date: 2009-02-23 19:06:32Z   User: JasonO 
*  
*  Revision: 10   Date: 2009-02-23 16:50:51Z   User: JasonO 
*  Truncating fractional age to 2 decimal places. 
*  
*  Revision: 9   Date: 2009-01-07 01:11:16Z   User: nicka 
*  Added GetAgeInYears() 
*  
*  Revision: 8   Date: 2009-01-07 00:33:29Z   User: nicka 
*  Added GetAgeInMonths() calculation 
*  
*  Revision: 7   Date: 2008-12-29 21:50:09Z   User: DallonF 
*  Added GetCommaSeperatedInts() 
*  
*  Revision: 6   Date: 2008-12-15 22:20:26Z   User: DallonF 
*  Added ToDataTable(this IEnumerable<T>) method 
*  
*  Revision: 5   Date: 2008-12-10 00:28:31Z   User: JasonO 
*  Updating date util class. 
*  
*  Revision: 4   Date: 2008-12-03 22:43:44Z   User: JasonO 
*  Addign DateUtils class w/ fractional age static method. 
*  
*  Revision: 3   Date: 2008-07-10 21:49:01Z   User: nicka 
**********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using System.Reflection;
using System.Linq;

namespace Arena.Custom.Cccev.DataUtils
{
    /// <summary>
    /// Methods relating to the database
    /// </summary>
    public static class DatabaseUtils
    {
        /// <summary>
        /// Returns a DataTable based on an IEnumerable. Used for objects such as the ArenaDataGrid which expect a DataTable.
        /// </summary>
        /// <typeparam name="T">The type of the list.</typeparam>
        /// <param name="?">The list</param>
        /// <returns>DataTable based on the list.</returns>
        public static DataTable ToDataTable<T>(this IEnumerable<T> list)
        {
            DataTable result = new DataTable();
            Type t = typeof(T);
            var colNames = t.GetProperties()
                .Where(p => p.CanRead)
                .Select(p => p.Name);
            foreach (string colName in colNames)
            {
                result.Columns.Add(colName);
            }
            foreach (T item in list)
            {
                DataRow row = result.Rows.Add();
                foreach (DataColumn col in result.Columns)
                {
                    row[col] = t.GetProperty(col.ColumnName).GetValue(item, null);
                }
            }
            return result;
        }
    }

	/// <summary>
	/// Methods relating to email and email addresses.
	/// </summary>
	public class EmailUtils
	{
		/// <summary>
		/// Returns true if the given string is a valid email address.
		/// </summary>
		/// <param name="email">The string to validate</param>
		/// <returns>true if valid email, false otherwise</returns>
		public static bool IsValidEmail(string email)
		{
			return Regex.IsMatch(email, @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
		}
	}

	/// <summary>
	/// Methods relating to string manipulation.
	/// </summary>
	public static class StringUtils
	{
		/// <summary>
		/// Truncates a string	
		/// </summary>
		/// <param name="value">The string to truncate</param>
		/// <param name="length">The length at which to truncate the string</param>
		/// <returns>Returns the truncated string</returns>
		public static string GetTruncatedString(string value, int length)
		{
			if (value.Length > length)
			{
				return value.Substring(0, length - 2) + "...";
			}
			return value;
		}

        public static IEnumerable<int> GetCommaSeperatedInts(string ints)
        {
            return ints.Split(',').Where(s => s.Trim() != String.Empty).Select(s => int.Parse(s));
        }

		/// <summary>
		/// Converts a string to an integer if possible
		/// </summary>
		/// <param name="s">The string to convert</param>
		/// <returns>The numerical value of the string, or -1 if string could not be converted.</returns>
        public static int ToInt32(this string s)
        {
            int result = -1;
			if (s == null || !int.TryParse(s.Trim(), out result ) )
			{
				result = -1;
			}
			return result;
        }
	}

    /// <summary>
    /// Methods relating to datetime information.
    /// </summary>
    public static class DateUtils
    {
        /// <summary>
        /// Calculates fractional age based on datetime passed in.  Will return a decimal value truncated to 3 decimal places.
        /// </summary>
        /// <param name="birthdate"></param>
        /// <returns>fractional age truncated to 3 decimal places</returns>
		public static decimal GetFractionalAge( DateTime birthdate )
		{
			// get the last birthday
			DateTime today = DateTime.Now;
			int years = today.Year - birthdate.Year;
			DateTime last = birthdate.AddYears( years );
			if ( last > today )
			{
				last = last.AddYears( -1 );
				years--;
			}
			// get the next birthday
			DateTime next = last.AddYears( 1 );
			// calculate the number of days between them
			double yearDays = ( next - last ).Days;
			// calcluate the number of days since last birthday
			double days = ( today - last ).Days;
			// calculate exaxt age
			double exactAge = (double)years + ( days / yearDays );
			
			// now return a decimal which includes trailing zeros
			string age = exactAge.ToString( "#0.00000" );
			string truncatedAge = age.Substring( 0, age.LastIndexOf( '.' ) + 4 );

			return decimal.Parse( truncatedAge );
		}

		/// <summary>
		/// Calculates the age in whole years for the given birthday.
		/// </summary>
		/// <param name="birthday">A birthdate</param>
		/// <returns>number of whole years</returns>
		public static int GetAgeInYears( DateTime birthday )
		{
			int monthDelta = GetDeltaInMonths( birthday, DateTime.Now );
			return monthDelta / 12;
		}

		/// <summary>
		/// Calculates the age in whole months for the given birthday.
		/// </summary>
		/// <param name="birthday">A birthdate</param>
		/// <returns>number of whole months</returns>
		public static int GetAgeInMonths( DateTime birthday )
		{
			return GetDeltaInMonths( birthday, DateTime.Now );
		}

		/// <summary>
		/// An algorthim to determine the number of whole months
		/// between two dates (by Greg Golden).
		/// </summary>
		/// <param name="then">A date.</param>
		/// <param name="now">Another date.</param>
		/// <returns>number of whole months between the two dates</returns>
		public static int GetDeltaInMonths( DateTime then, DateTime now )
		{
			int thenMonthsSince1900 = 12 * ( then.Year - 1900 ) + then.Month;
			int nowMonthsSince1900 = 12 * ( now.Year - 1900 ) + now.Month;

			int monthsOld = nowMonthsSince1900 - thenMonthsSince1900;

			if ( now.Day < then.Day )
			{
				monthsOld--;
			}

			return monthsOld;
		}
    }
}
